# -*- coding: utf-8 -*-
import json
from functools import partial

from django.conf import settings
from django.utils.encoding import smart_unicode
from future.utils import raise_with_traceback
from pymongo.errors import PyMongoError
from redis import RedisError
from sqlalchemy.exc import SQLAlchemyError

from common import orm
from common.admin.db import get_user
from common.utils import JsonResponse
from common.utils import track_logging
from common.utils.exceptions import (Error, ServerError, DbError,
                                     CacheError, GCodeError)
from common.utils.respcode import StatusCodeDict
from common.utils.safedog import google_verify_token

_LOGGER = track_logging.getLogger(__name__)


def _wrap2json(data):
    if data is None:
        data = {}
    elif isinstance(data, dict) or isinstance(data, list):
        return JsonResponse(dict(status=0, msg='', data=data), status=200)
    else:
        return data


def response_wrapper(func):
    def _wrapper(request, *args, **kwargs):

        if settings.DEBUG:
            return _wrap2json(func(request, *args, **kwargs))

        try:
            return _wrap2json(func(request, *args, **kwargs))
        except ServerError as e:
            _LOGGER.exception('server error!')
            return JsonResponse(
                dict(status=e.STATUS,
                     msg=unicode(e) or StatusCodeDict.get(e.STATUS)),
                status=e.HTTPCODE)
        except Error as e:
            if 'Error' == e.__class__.__name__:
                _LOGGER.exception('catched error %s in %s',
                                  e.__class__.__name__, request.path)
            else:
                _LOGGER.warn('catched error %s(%s) in %s',
                             e.__class__.__name__, unicode(e), request.path)
            return JsonResponse(
                dict(status=e.STATUS,
                     msg=e.message or StatusCodeDict.get(e.STATUS)),
                status=e.HTTPCODE)
        except Exception as e:
            _LOGGER.exception('unexcepted error!!')
            return JsonResponse(
                dict(status=Error.STATUS, msg=unicode(e) or u'未知错误'),
                status=Error.HTTPCODE)

    return _wrapper


def common_sql_wrapper(orm):
    def handler(func):
        def _wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except SQLAlchemyError as e:
                orm.session.rollback()
                raise_with_traceback(DbError(e))
            except Error:
                orm.session.rollback()
                raise
            except Exception as e:
                orm.session.rollback()
                raise_with_traceback(Error(e))
            finally:
                orm.session.close()

        return _wrapper

    return handler


sql_wrapper = partial(common_sql_wrapper(orm=orm))


def cache_wrapper(func):
    def _wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except RedisError as e:
            raise_with_traceback(CacheError(e))
        except Error:
            raise
        except Exception as e:
            raise_with_traceback(Error(e))

    return _wrapper


def mongo_wrapper(func):
    def _wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except PyMongoError as e:
            raise_with_traceback(DbError(e))
        except Error:
            raise
        except Exception as e:
            raise_with_traceback(Error(e))

    return _wrapper


def fake_safe_code(func):
    def _wrapper(*args, **kwargs):
        if hasattr(settings, 'IS_PRODUCTION_ENV') and not settings.IS_PRODUCTION_ENV:
            return True
        else:
            func(*args, **kwargs)

    return _wrapper


@fake_safe_code
def _check_safe_code(req):
    _LOGGER.info('check_safe_code in : %s', req.body)
    info = json.loads(smart_unicode(req.body))
    g_code = info.get('g_code', '')
    if req.path.startswith('/pay/admin'):
        if get_user(req.user_id).use_safe_dog:
            if not google_verify_token(req.user_id, g_code, '127.0.0.1'):
                raise GCodeError()


def safe_wrapper(func):
    def _wrapped(request, *args, **kwargs):
        _check_safe_code(request)
        return func(request, *args, **kwargs)

    return _wrapped
